Assignment 1. Perception Visualization

Question 1.

olive$linolenic2 <- cut_interval(olive$linolenic, n=4)

The plots demonstrate the preattentive perception problem. With the first plot it is not easy to make out boundaries while in the second plot one can easily perceive boundaries.

Question 2.

It is more difficult to differentiate between the categories using angle compared to using color and size. The spoke diagram requires a combination of line length (2.8 bits) and line orientation (3 bits) which is more than size (2.2 bits) and color brightness (2.1 bits)

pal_vs_ole_angle <- ggplot(olive, aes(oleic, palmitic)) +
  geom_point() +
  geom_spoke(aes(angle=as.numeric(linolenic2),radius= 35)) +
  ggtitle("Palmitic vs Oleic angle by Linolenic") +
  theme_minimal()
pal_vs_ole_angle

Question 3.

For the first plot it is difficult to judge boundaries because the color takes a continuous scale, it requires more attention to differentiate the color scales (attentive). For the second graph with region as factors it is quick to judge boundaries hence preattentive.

Question 4

This is an attentive perception problem. It is quite difficult to process information and judge the boundaries on the three groups. One has to analyse color shape and size and position on the X and Y axis at the same time.

o_vs_e1 <- ggplot(olive, aes(x=eicosenoic, y= oleic)) + 
  geom_point(aes(color=linoleic2, size=palmitoleic2, shape=palmitic2)) +
  ggtitle("Oleic vs Eicosenoic")+
  theme_minimal()
o_vs_e1

Question 5.

The color dominates every other aesthetic hence it makes it easier to notice the boundaries despite shape and size. Treisman’s theory (Treisman 1985) on visual analysis “search for the presence of a visual primitive is automatic and parallel, whereas search for the absence of the same feature is serial and requires focused attention”.

o_vs_e2 <- ggplot(olive, aes(x=oleic, y=eicosenoic)) + 
  geom_point(aes(color=Region, size=palmitoleic2, shape=palmitic2))
o_vs_e2

Question 6.

Without labels on the individual sections, the different areas appear to have the same proportions. This demonstrates the relative judgement problem.

Question 7.

The contour plot shows that there are observations in areas where in actual scatter plot there aren’t any. The contour plot shows that there are five distinct density areas (two sparsely dense and three highly dense).

l_vs_e <- ggplot(olive, aes(x = eicosenoic, y = linoleic)) +
  geom_density_2d()+
  theme_minimal() +
  ggtitle("Contour plot of linoleic vs eicosenoic")
  
l_vs_e  

Assignment 2: Multidimensional Scaling of a high-dimensional object

Question1

The xlsx file is converted to a csv file, makes it easier to load the data without extra packages. It is reasonable to scale the data because they have different ranges so that features with large scales do not dominate. Example, comparing maximum value and minimum value for “AB” and “Home runs per game”. The two are on totally different scales.

# range of AB
range1 <- max(baseball$AB) -  min(baseball$AB)
range1
[1] 340
# range of HR per game
range2 <- max(baseball$HR.per.game) - min(baseball$HR.per.game)
range2
[1] 0.8039644

The density plot below graphically explains why scaling is needed. Appropriate density should be similar to log normal density.

plot(density(as.matrix(baseball[3:ncol(baseball)])), main = "Density of baseball numeric variables ")

Question 2

# Getting distance between points using Minkowski
mink_d <- dist(baseball2, method = "minkowski", p =2)
# get 2 column vector with fitted configuration 
resid <- isoMDS(mink_d, k=2 )
initial  value 19.856833 
iter   5 value 16.319153
iter  10 value 16.046215
final  value 15.935476 
converged
# getting the coordinates
coords <- resid$points
# convert coords to dataframe
coordsMDS <- as.data.frame(coords)
# cbind to get column Team and League
coordsMDS2 <- cbind(baseball[ , 1:2], coordsMDS)

There appears to be a difference between the two leagues; most of the NL league teams are on the second and third quadrant (negative V2) while most of the AL league teams are on the first and fourth quadrant (positive V2). The y-axis “V2” has the best differentiation between the leagues. The Boston Red Sox, Atlanta Braves and Philadelphia Philies appear to be outliers. The AL teams are closely clustered together compared to the NL teams.

# Shepard diagrams assess the goodness-of-fit of MDS techniques
# run shep on points from isoMDS and using same distance as calculated in previous step
shep <- Shepard(mink_d, coords)
# plotly
plot_ly()%>%
  add_markers(x=~delta, y=~D, hoverinfo = 'text',
        text = ~paste('Obj1: ', rownames(baseball3)[index1],
                      '<br> Obj2: ', rownames(baseball3)[index2])) %>%
  #if nonmetric MDS inolved
  add_lines(x=~shep$x, y=~shep$yf) %>%
  layout(title = "Shepard's plot")
# Variables that seem to have strongest postive relationship
# HR per game:
myplot(d4, "HR.per.game")

# HR
myplot(d4, "X3B")

Per the plot, HR per game and HR have the same scatter points. The two have strongest positive connection to V2 while X3B has the strongest negative connection to V2.

Appendix

olive <- read.csv("olive.csv", sep = ",", header = TRUE)
library(ggplot2)
library(plotly)
library(MASS)
library(gridExtra)
p_vs_o <- ggplot(olive, aes(x=oleic, y=palmitic,
                     color = linolenic)) +
  geom_point() +
  ggtitle("Dependence of Palmitic on Oleic colored by numeric Linolenic") +
  theme_minimal()
  
p_vs_o
olive$linolenic2 <- cut_interval(olive$linolenic, n=4)
p_vs_o2 <- ggplot(olive, aes(x=oleic, y=palmitic, color = linolenic2)) + 
  geom_point() +
  ggtitle("Dependence of Palmitic on Oleic colored by discretized Linolenic") +
  theme_minimal()
  #scale_fill_manual(name = "Discrete Linolenic")

p_vs_o2
pal_vs_ole_col <- ggplot(olive, aes(oleic, palmitic)) +
  geom_point(aes(color=linolenic2))+
  ggtitle("Oleic vs Palmitic colored by Discretized Linolenic") +
  theme_minimal()

pal_vs_ole_col
pal_vs_ole_size <- ggplot(olive, aes(oleic, palmitic)) +
  geom_point(aes(size=linolenic2)) +
  ggtitle("Oleic vs Palmitic sized by Discretized Linolenic") +
  theme_minimal()

pal_vs_ole_size
pal_vs_ole_angle <- ggplot(olive, aes(oleic, palmitic)) +
  geom_point() +
  geom_spoke(aes(angle=as.numeric(linolenic2),radius= 35)) +
  ggtitle("Palmitic vs Oleic angle by Linolenic") +
  theme_minimal()

pal_vs_ole_angle
o_vs_e <- ggplot(olive, aes(x= eicosenoic, y = oleic, color = Region)) + 
  geom_point() +
  ggtitle(" Oleic vs Eicosenoic colored by Region") +
  theme_minimal()
o_vs_e
o_vs_e0 <- ggplot(olive, aes(x=eicosenoic, y = oleic , color = as.factor(Region)))+
  geom_point() +
  ggtitle("Oleic vs Eicosenoic colored by factored Region") +
  theme_minimal()

o_vs_e0
olive$linoleic2 <- cut_interval(olive$linoleic, n=3)
olive$palmitic2 <- cut_interval(olive$palmitic, n=3)
olive$palmitoleic2 <- cut_interval(olive$palmitoleic, n=3)
o_vs_e1 <- ggplot(olive, aes(x=eicosenoic, y= oleic)) + 
  geom_point(aes(color=linoleic2, size=palmitoleic2, shape=palmitic2)) +
  ggtitle("Oleic vs Eicosenoic")+
  theme_minimal()

o_vs_e1
o_vs_e2 <- ggplot(olive, aes(x=oleic, y=eicosenoic)) + 
  geom_point(aes(color=Region, size=palmitoleic2, shape=palmitic2))

o_vs_e2
plot_ly(data = olive, labels=~Area, type = 'pie', showlegend = TRUE, textinfo = "text", text = "") %>%
  layout(title = 'Proportion of Oils from different regions',
        xaxis = list(showgrid = F, zeroline = F, showticklables = F),
         yaxis = list(showgrid = F, zeroline = F, showticklables = F))

l_vs_e <- ggplot(olive, aes(x = eicosenoic, y = linoleic)) +
  geom_density_2d()+
  theme_minimal() +
  ggtitle("Contour plot of linoleic vs eicosenoic")
  
l_vs_e  
l_vs_e1 <- ggplot(olive, aes(x=eicosenoic, y = linoleic))+
  geom_point() +
  ggtitle("linoleic vs Eicosenoic Scatter plot ") +
  theme_minimal()

l_vs_e1
# reading the data
baseball <- read.csv("baseball-2016.csv", sep = ",", header = TRUE)
# range of AB
range1 <- max(baseball$AB) -  min(baseball$AB)
range1
# range of HR per game
range2 <- max(baseball$HR.per.game) - min(baseball$HR.per.game)

range2
plot(density(as.matrix(baseball[3:ncol(baseball)])), main = "Density of baseball numeric variables ")
# scale the 26 numeric columns
baseball2 <- scale(baseball[ ,3:ncol(baseball)])
# Getting distance between points using Minkowski
mink_d <- dist(baseball2, method = "minkowski", p =2)
# get 2 column vector with fitted configuration 
resid <- isoMDS(mink_d, k=2 )

# getting the coordinates
coords <- resid$points

# convert coords to dataframe
coordsMDS <- as.data.frame(coords)

# cbind to get column Team and League
coordsMDS2 <- cbind(baseball[ , 1:2], coordsMDS)
# plot the new dimension and color by  League
plot_ly(coordsMDS2, x= ~V1, y = ~V2, type ="scatter", hovertext = ~ Team,
            color = ~League, colors = c("#0444BF","#F46A4E"))
# Shepard diagrams assess the goodness-of-fit of MDS techniques
# run shep on points from isoMDS and using same distance as calculated in previous step
shep <- Shepard(mink_d, coords)
# convert the distance to numeric
delta <- as.numeric(mink_d)
# All the coords in one column
D <- as.numeric(dist(coords))
# create a square matrix with dimensions from the rows of coords
# n as rows 
n = nrow(coords)

# index as empyt matrix
index <- matrix(1:n, nrow = n, ncol = n)

# get index of the lower triangle of the index matrix and convert it to numeric
index1 <- as.numeric(index[lower.tri(index)])

# same procedur
n = nrow(coords)

index <- matrix(1:n, nrow=n, ncol=n, byrow = T)

index2 <- as.numeric(index[lower.tri(index)])
# i dont want to edit original data
baseball3 <- baseball

rownames(baseball3) <-baseball3[ ,1]

# plotly
plot_ly()%>%
  add_markers(x=~delta, y=~D, hoverinfo = 'text',
        text = ~paste('Obj1: ', rownames(baseball3)[index1],
                      '<br> Obj2: ', rownames(baseball3)[index2])) %>%
  #if nonmetric MDS inolved
  add_lines(x=~shep$x, y=~shep$yf) %>%
  layout(title = "Shepard's plot")
# get MDS variable V2 and cbind with points from isoMDS
d4 <- cbind(baseball[ ,1:2], coords[,2], baseball2[,])

# rename col3 to V2
colnames(d4)[3] <- c("V2")
# function to successively get plots of V2 vs other variables
myplot <-function(df, y_string){
  ggplot(df, aes_string(x = "V2", y = y_string, color = "League"))+
    geom_point()+
    geom_vline(xintercept = 0, color = "black")+
    geom_hline(yintercept = 0, color = "black")
}
# Variables that seem to have strongest postive relationship
# HR per game:
myplot(d4, "HR.per.game")
# X3B
myplot(d4, "X3B")

References

Treisman, Anne. 1985. “Preattentive Processing in Vision.” Computer Vision, Graphics, and Image Processing 31: 156–77. doi:https://doi.org/10.1016/S0734-189X(85)80004-9.

LS0tDQp0aXRsZTogIlZpc3VhbGl6YXRpb24gTGFiIDIiDQphdXRob3I6ICJSb3NobmkgU3VuZGFyYW11cnRoeSAocm9zc3U4MDkpOyBCcmlhbiBNYXNpbmRlIChicmltYTc0OCkiDQpkYXRlOiAiMTcgU2VwdGVtYmVyIDIwMTgiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdGhlbWU6IGpvdXJuYWwNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQpmb250c2l6ZTogMTFwdA0KYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KLS0tDQoNCiMjIyBBc3NpZ25tZW50IDEuIFBlcmNlcHRpb24gVmlzdWFsaXphdGlvbg0KDQpgYGB7ciBkYXRhLCBlY2hvID0gRkFMU0V9DQpvbGl2ZSA8LSByZWFkLmNzdigib2xpdmUuY3N2Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBUUlVFKQ0KYGBgDQoNCmBgYHtyIGxpYnJhcmllcywgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KYGBgDQoNCiMjIyMgUXVlc3Rpb24gMS4NCmBgYHtyIHF1ZXN0aW9uMV9hLCBlY2hvPUZBTFNFfQ0KcF92c19vIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9b2xlaWMsIHk9cGFsbWl0aWMsDQogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxpbm9sZW5pYykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2d0aXRsZSgiRGVwZW5kZW5jZSBvZiBQYWxtaXRpYyBvbiBPbGVpYyBjb2xvcmVkIGJ5IG51bWVyaWMgTGlub2xlbmljIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCiAgDQpwX3ZzX28NCmBgYA0KDQpgYGB7ciBjdXRfaW50ZXJ2YWx9DQpvbGl2ZSRsaW5vbGVuaWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRsaW5vbGVuaWMsIG49NCkNCmBgYA0KDQpUaGUgcGxvdHMgZGVtb25zdHJhdGUgdGhlIHByZWF0dGVudGl2ZSBwZXJjZXB0aW9uIHByb2JsZW0uIFdpdGggdGhlIGZpcnN0IHBsb3QgaXQgaXMgbm90IGVhc3kgdG8gbWFrZSBvdXQgYm91bmRhcmllcyB3aGlsZSBpbiB0aGUgc2Vjb25kIHBsb3Qgb25lIGNhbiBlYXNpbHkgcGVyY2VpdmUgYm91bmRhcmllcy4NCg0KYGBge3IgcXVlc3Rpb24xX2IsIGVjaG89RkFMU0V9DQpwX3ZzX28yIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9b2xlaWMsIHk9cGFsbWl0aWMsIGNvbG9yID0gbGlub2xlbmljMikpICsgDQogIGdlb21fcG9pbnQoKSArDQogIGdndGl0bGUoIkRlcGVuZGVuY2Ugb2YgUGFsbWl0aWMgb24gT2xlaWMgY29sb3JlZCBieSBkaXNjcmV0aXplZCBMaW5vbGVuaWMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KICAjc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJEaXNjcmV0ZSBMaW5vbGVuaWMiKQ0KDQpwX3ZzX28yDQpgYGANCg0KIyMjIyBRdWVzdGlvbiAyLg0KSXQgaXMgbW9yZSBkaWZmaWN1bHQgdG8gZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIHRoZSBjYXRlZ29yaWVzIHVzaW5nIGFuZ2xlIGNvbXBhcmVkIHRvIHVzaW5nIGNvbG9yIGFuZCBzaXplLiBUaGUgc3Bva2UgZGlhZ3JhbSByZXF1aXJlcyBhIGNvbWJpbmF0aW9uIG9mIGxpbmUgbGVuZ3RoICgyLjggYml0cykgYW5kIGxpbmUgb3JpZW50YXRpb24gKDMgYml0cykgd2hpY2ggaXMgbW9yZSB0aGFuIHNpemUgKDIuMiBiaXRzKSBhbmQgY29sb3IgYnJpZ2h0bmVzcyAoMi4xIGJpdHMpDQoNCmBgYHtyIHF1ZXN0aW9uIDJfYSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCnBhbF92c19vbGVfY29sIDwtIGdncGxvdChvbGl2ZSwgYWVzKG9sZWljLCBwYWxtaXRpYykpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9bGlub2xlbmljMikpKw0KICBnZ3RpdGxlKCJPbGVpYyB2cyBQYWxtaXRpYyBjb2xvcmVkIGJ5IERpc2NyZXRpemVkIExpbm9sZW5pYyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnBhbF92c19vbGVfY29sDQpgYGANCg0KDQpgYGB7ciBxdWVzdGlvbiAyX2IsIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1GQUxTRX0NCnBhbF92c19vbGVfc2l6ZSA8LSBnZ3Bsb3Qob2xpdmUsIGFlcyhvbGVpYywgcGFsbWl0aWMpKSArDQogIGdlb21fcG9pbnQoYWVzKHNpemU9bGlub2xlbmljMikpICsNCiAgZ2d0aXRsZSgiT2xlaWMgdnMgUGFsbWl0aWMgc2l6ZWQgYnkgRGlzY3JldGl6ZWQgTGlub2xlbmljIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KcGFsX3ZzX29sZV9zaXplDQpgYGANCg0KYGBge3IgcXVlc3Rpb24gMl9jLCB3YXJuaW5nPUZBTFNFfQ0KcGFsX3ZzX29sZV9hbmdsZSA8LSBnZ3Bsb3Qob2xpdmUsIGFlcyhvbGVpYywgcGFsbWl0aWMpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc3Bva2UoYWVzKGFuZ2xlPWFzLm51bWVyaWMobGlub2xlbmljMikscmFkaXVzPSAzNSkpICsNCiAgZ2d0aXRsZSgiUGFsbWl0aWMgdnMgT2xlaWMgYW5nbGUgYnkgTGlub2xlbmljIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KcGFsX3ZzX29sZV9hbmdsZQ0KYGBgDQoNCiMjIyMgUXVlc3Rpb24gMy4gDQpGb3IgdGhlIGZpcnN0IHBsb3QgaXQgaXMgZGlmZmljdWx0IHRvIGp1ZGdlIGJvdW5kYXJpZXMgYmVjYXVzZSB0aGUgY29sb3IgdGFrZXMgYSBjb250aW51b3VzIHNjYWxlLCBpdCByZXF1aXJlcyBtb3JlIGF0dGVudGlvbiB0byBkaWZmZXJlbnRpYXRlIHRoZSBjb2xvciBzY2FsZXMgKGF0dGVudGl2ZSkuIEZvciB0aGUgc2Vjb25kIGdyYXBoIHdpdGggcmVnaW9uIGFzIGZhY3RvcnMgaXQgaXMgcXVpY2sgdG8ganVkZ2UgYm91bmRhcmllcyBoZW5jZSBwcmVhdHRlbnRpdmUuDQoNCmBgYHtyIFF1ZXN0aW9uMywgZWNobz1GQUxTRX0NCm9fdnNfZSA8LSBnZ3Bsb3Qob2xpdmUsIGFlcyh4PSBlaWNvc2Vub2ljLCB5ID0gb2xlaWMsIGNvbG9yID0gUmVnaW9uKSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2d0aXRsZSgiIE9sZWljIHZzIEVpY29zZW5vaWMgY29sb3JlZCBieSBSZWdpb24iKSArDQogIHRoZW1lX21pbmltYWwoKQ0Kb192c19lDQpgYGANCg0KYGBge3IgcXVlc3Rpb24zX2IsIGVjaG89RkFMU0V9DQpvX3ZzX2UwIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9ZWljb3Nlbm9pYywgeSA9IG9sZWljICwgY29sb3IgPSBhcy5mYWN0b3IoUmVnaW9uKSkpKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZ3RpdGxlKCJPbGVpYyB2cyBFaWNvc2Vub2ljIGNvbG9yZWQgYnkgZmFjdG9yZWQgUmVnaW9uIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0Kb192c19lMA0KYGBgDQoNCiMjIyMgUXVlc3Rpb24gNA0KDQpUaGlzIGlzIGFuIGF0dGVudGl2ZSBwZXJjZXB0aW9uIHByb2JsZW0uIEl0IGlzIHF1aXRlIGRpZmZpY3VsdCB0byBwcm9jZXNzIGluZm9ybWF0aW9uIGFuZCBqdWRnZSB0aGUgYm91bmRhcmllcyBvbiB0aGUgdGhyZWUgZ3JvdXBzLiBPbmUgaGFzIHRvIGFuYWx5c2UgY29sb3Igc2hhcGUgYW5kIHNpemUgYW5kIHBvc2l0aW9uIG9uIHRoZSBYIGFuZCBZIGF4aXMgYXQgdGhlIHNhbWUgdGltZS4NCiANCmBgYHtyIGRpc2NyZXRpemF0aW9uLCBlY2hvPUZBTFNFfQ0Kb2xpdmUkbGlub2xlaWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRsaW5vbGVpYywgbj0zKQ0Kb2xpdmUkcGFsbWl0aWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRwYWxtaXRpYywgbj0zKQ0Kb2xpdmUkcGFsbWl0b2xlaWMyIDwtIGN1dF9pbnRlcnZhbChvbGl2ZSRwYWxtaXRvbGVpYywgbj0zKQ0KYGBgDQoNCmBgYHtyIHF1ZXN0aW9uNCwgd2FybmluZz1GQUxTRX0NCm9fdnNfZTEgPC0gZ2dwbG90KG9saXZlLCBhZXMoeD1laWNvc2Vub2ljLCB5PSBvbGVpYykpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWxpbm9sZWljMiwgc2l6ZT1wYWxtaXRvbGVpYzIsIHNoYXBlPXBhbG1pdGljMikpICsNCiAgZ2d0aXRsZSgiT2xlaWMgdnMgRWljb3Nlbm9pYyIpKw0KICB0aGVtZV9taW5pbWFsKCkNCg0Kb192c19lMQ0KYGBgDQoNCiMjIyMgUXVlc3Rpb24gNS4NClRoZSBjb2xvciBkb21pbmF0ZXMgZXZlcnkgb3RoZXIgYWVzdGhldGljIGhlbmNlIGl0IG1ha2VzIGl0IGVhc2llciB0byBub3RpY2UgdGhlIGJvdW5kYXJpZXMgZGVzcGl0ZSBzaGFwZSBhbmQgc2l6ZS4gVHJlaXNtYW4ncyB0aGVvcnkgW0B0cmVpc21hbl0gb24gdmlzdWFsIGFuYWx5c2lzICJzZWFyY2ggZm9yIHRoZSBwcmVzZW5jZSBvZiBhIHZpc3VhbCBwcmltaXRpdmUgaXMgYXV0b21hdGljIGFuZA0KcGFyYWxsZWwsIHdoZXJlYXMgc2VhcmNoIGZvciB0aGUgYWJzZW5jZSBvZiB0aGUgc2FtZSBmZWF0dXJlIGlzIHNlcmlhbCBhbmQgcmVxdWlyZXMgZm9jdXNlZA0KYXR0ZW50aW9uIi4gDQoNCmBgYHtyIHF1ZXN0aW9uNSwgd2FybmluZz1GQUxTRX0NCm9fdnNfZTIgPC0gZ2dwbG90KG9saXZlLCBhZXMoeD1vbGVpYywgeT1laWNvc2Vub2ljKSkgKyANCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9UmVnaW9uLCBzaXplPXBhbG1pdG9sZWljMiwgc2hhcGU9cGFsbWl0aWMyKSkNCg0Kb192c19lMg0KYGBgDQoNCiMjIyMgUXVlc3Rpb24gNi4NCg0KV2l0aG91dCBsYWJlbHMgb24gdGhlIGluZGl2aWR1YWwgc2VjdGlvbnMsIHRoZSBkaWZmZXJlbnQgYXJlYXMgYXBwZWFyIHRvIGhhdmUgdGhlIHNhbWUgcHJvcG9ydGlvbnMuIFRoaXMgZGVtb25zdHJhdGVzIHRoZSByZWxhdGl2ZSBqdWRnZW1lbnQgcHJvYmxlbS4NCmBgYHtyIHF1ZXN0aW9uNiwgZWNobz1GQUxTRX0NCnBsb3RfbHkoZGF0YSA9IG9saXZlLCBsYWJlbHM9fkFyZWEsIHR5cGUgPSAncGllJywgc2hvd2xlZ2VuZCA9IFRSVUUsIHRleHRpbmZvID0gInRleHQiLCB0ZXh0ID0gIiIpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAnUHJvcG9ydGlvbiBvZiBPaWxzIGZyb20gZGlmZmVyZW50IHJlZ2lvbnMnLA0KICAgICAgICB4YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGLCB6ZXJvbGluZSA9IEYsIHNob3d0aWNrbGFibGVzID0gRiksDQogICAgICAgICB5YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGLCB6ZXJvbGluZSA9IEYsIHNob3d0aWNrbGFibGVzID0gRikpDQoNCmBgYA0KDQoNCiMjIyMgUXVlc3Rpb24gNy4NCg0KVGhlIGNvbnRvdXIgcGxvdCBzaG93cyB0aGF0IHRoZXJlIGFyZSBvYnNlcnZhdGlvbnMgaW4gYXJlYXMgd2hlcmUgaW4gYWN0dWFsIHNjYXR0ZXIgcGxvdCB0aGVyZSBhcmVuJ3QgYW55LiBUaGUgY29udG91ciBwbG90IHNob3dzIHRoYXQgdGhlcmUgYXJlIGZpdmUgZGlzdGluY3QgZGVuc2l0eSBhcmVhcyAodHdvIHNwYXJzZWx5IGRlbnNlIGFuZCB0aHJlZSBoaWdobHkgZGVuc2UpLg0KDQpgYGB7ciBxdWVzdGlvbjd9DQpsX3ZzX2UgPC0gZ2dwbG90KG9saXZlLCBhZXMoeCA9IGVpY29zZW5vaWMsIHkgPSBsaW5vbGVpYykpICsNCiAgZ2VvbV9kZW5zaXR5XzJkKCkrDQogIHRoZW1lX21pbmltYWwoKSArDQogIGdndGl0bGUoIkNvbnRvdXIgcGxvdCBvZiBsaW5vbGVpYyB2cyBlaWNvc2Vub2ljIikNCiAgDQpsX3ZzX2UgIA0KYGBgDQoNCg0KYGBge3IgcXVlc3Rpb243X2IsIGVjaG89RkFMU0V9DQpsX3ZzX2UxIDwtIGdncGxvdChvbGl2ZSwgYWVzKHg9ZWljb3Nlbm9pYywgeSA9IGxpbm9sZWljKSkrDQogIGdlb21fcG9pbnQoKSArDQogIGdndGl0bGUoImxpbm9sZWljIHZzIEVpY29zZW5vaWMgU2NhdHRlciBwbG90ICIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmxfdnNfZTENCmBgYA0KDQoNCiMjIyBBc3NpZ25tZW50IDI6IE11bHRpZGltZW5zaW9uYWwgU2NhbGluZyBvZiBhIGhpZ2gtZGltZW5zaW9uYWwgb2JqZWN0DQoNCmBgYHtyIGJhc2VfZGF0YSwgZWNobz0gRkFMU0V9DQojIHJlYWRpbmcgdGhlIGRhdGENCmJhc2ViYWxsIDwtIHJlYWQuY3N2KCJiYXNlYmFsbC0yMDE2LmNzdiIsIHNlcCA9ICIsIiwgaGVhZGVyID0gVFJVRSkNCmBgYA0KDQojIyMjIFF1ZXN0aW9uMQ0KVGhlIHhsc3ggZmlsZSBpcyBjb252ZXJ0ZWQgdG8gYSBjc3YgZmlsZSwgbWFrZXMgaXQgZWFzaWVyIHRvIGxvYWQgdGhlIGRhdGEgd2l0aG91dCBleHRyYSBwYWNrYWdlcy4gSXQgaXMgcmVhc29uYWJsZSB0byBzY2FsZSB0aGUgZGF0YSBiZWNhdXNlIHRoZXkgaGF2ZSBkaWZmZXJlbnQgcmFuZ2VzIHNvIHRoYXQgZmVhdHVyZXMgd2l0aCBsYXJnZSBzY2FsZXMgZG8gbm90IGRvbWluYXRlLiBFeGFtcGxlLCBjb21wYXJpbmcgbWF4aW11bSB2YWx1ZSBhbmQgbWluaW11bSB2YWx1ZSBmb3IgIkFCIiBhbmQgIkhvbWUgcnVucyBwZXIgZ2FtZSIuIFRoZSB0d28gYXJlIG9uIHRvdGFsbHkgZGlmZmVyZW50IHNjYWxlcy4NCg0KYGBge3IgcmFuZ2VfYWJ9DQojIHJhbmdlIG9mIEFCDQpyYW5nZTEgPC0gbWF4KGJhc2ViYWxsJEFCKSAtICBtaW4oYmFzZWJhbGwkQUIpDQpyYW5nZTENCmBgYA0KDQpgYGB7ciByYW5nZV9ocnBnfQ0KIyByYW5nZSBvZiBIUiBwZXIgZ2FtZQ0KcmFuZ2UyIDwtIG1heChiYXNlYmFsbCRIUi5wZXIuZ2FtZSkgLSBtaW4oYmFzZWJhbGwkSFIucGVyLmdhbWUpDQoNCnJhbmdlMg0KYGBgDQoNClRoZSBkZW5zaXR5IHBsb3QgYmVsb3cgZ3JhcGhpY2FsbHkgZXhwbGFpbnMgd2h5IHNjYWxpbmcgaXMgbmVlZGVkLiBBcHByb3ByaWF0ZSBkZW5zaXR5IHNob3VsZCBiZSBzaW1pbGFyIHRvIGxvZyBub3JtYWwgZGVuc2l0eS4NCg0KYGBge3IgYmFzZV9kZW5zaXR5fQ0KcGxvdChkZW5zaXR5KGFzLm1hdHJpeChiYXNlYmFsbFszOm5jb2woYmFzZWJhbGwpXSkpLCBtYWluID0gIkRlbnNpdHkgb2YgYmFzZWJhbGwgbnVtZXJpYyB2YXJpYWJsZXMgIikNCmBgYA0KDQoNCiMjIyMgUXVlc3Rpb24gMg0KDQpgYGB7ciBzY2FsZSwgZWNobz1GQUxTRX0NCiMgc2NhbGUgdGhlIDI2IG51bWVyaWMgY29sdW1ucw0KYmFzZWJhbGwyIDwtIHNjYWxlKGJhc2ViYWxsWyAsMzpuY29sKGJhc2ViYWxsKV0pDQpgYGANCg0KYGBge3IgbWlua30NCiMgR2V0dGluZyBkaXN0YW5jZSBiZXR3ZWVuIHBvaW50cyB1c2luZyBNaW5rb3dza2kNCm1pbmtfZCA8LSBkaXN0KGJhc2ViYWxsMiwgbWV0aG9kID0gIm1pbmtvd3NraSIsIHAgPTIpDQpgYGANCg0KYGBge3IgaXNvTURTLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCiMgZ2V0IDIgY29sdW1uIHZlY3RvciB3aXRoIGZpdHRlZCBjb25maWd1cmF0aW9uIA0KcmVzaWQgPC0gaXNvTURTKG1pbmtfZCwgaz0yICkNCg0KIyBnZXR0aW5nIHRoZSBjb29yZGluYXRlcw0KY29vcmRzIDwtIHJlc2lkJHBvaW50cw0KDQojIGNvbnZlcnQgY29vcmRzIHRvIGRhdGFmcmFtZQ0KY29vcmRzTURTIDwtIGFzLmRhdGEuZnJhbWUoY29vcmRzKQ0KDQojIGNiaW5kIHRvIGdldCBjb2x1bW4gVGVhbSBhbmQgTGVhZ3VlDQpjb29yZHNNRFMyIDwtIGNiaW5kKGJhc2ViYWxsWyAsIDE6Ml0sIGNvb3Jkc01EUykNCmBgYA0KDQpgYGB7ciB2YXIsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQojIHBsb3QgdGhlIG5ldyBkaW1lbnNpb24gYW5kIGNvbG9yIGJ5ICBMZWFndWUNCnBsb3RfbHkoY29vcmRzTURTMiwgeD0gflYxLCB5ID0gflYyLCB0eXBlID0ic2NhdHRlciIsIGhvdmVydGV4dCA9IH4gVGVhbSwNCiAgICAgICAgICAgIGNvbG9yID0gfkxlYWd1ZSwgY29sb3JzID0gYygiIzA0NDRCRiIsIiNGNDZBNEUiKSkNCmBgYA0KDQpUaGVyZSBhcHBlYXJzIHRvIGJlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gbGVhZ3VlczsgbW9zdCBvZiB0aGUgTkwgbGVhZ3VlIHRlYW1zIGFyZSBvbiB0aGUgc2Vjb25kIGFuZCB0aGlyZCBxdWFkcmFudCAobmVnYXRpdmUgVjIpIHdoaWxlIG1vc3Qgb2YgdGhlIEFMIGxlYWd1ZSB0ZWFtcyBhcmUgb24gdGhlIGZpcnN0IGFuZCBmb3VydGggcXVhZHJhbnQgKHBvc2l0aXZlIFYyKS4gVGhlIHktYXhpcyAiVjIiIGhhcyB0aGUgYmVzdCBkaWZmZXJlbnRpYXRpb24gYmV0d2VlbiB0aGUgbGVhZ3Vlcy4gVGhlIEJvc3RvbiBSZWQgU294LCBBdGxhbnRhIEJyYXZlcyBhbmQgUGhpbGFkZWxwaGlhIFBoaWxpZXMgYXBwZWFyIHRvIGJlIG91dGxpZXJzLiBUaGUgQUwgdGVhbXMgYXJlIGNsb3NlbHkgY2x1c3RlcmVkIHRvZ2V0aGVyIGNvbXBhcmVkIHRvIHRoZSBOTCB0ZWFtcy4NCg0KYGBge3IgcXVlc3Rpb24zXzJ9DQojIFNoZXBhcmQgZGlhZ3JhbXMgYXNzZXNzIHRoZSBnb29kbmVzcy1vZi1maXQgb2YgTURTIHRlY2huaXF1ZXMNCiMgcnVuIHNoZXAgb24gcG9pbnRzIGZyb20gaXNvTURTIGFuZCB1c2luZyBzYW1lIGRpc3RhbmNlIGFzIGNhbGN1bGF0ZWQgaW4gcHJldmlvdXMgc3RlcA0Kc2hlcCA8LSBTaGVwYXJkKG1pbmtfZCwgY29vcmRzKQ0KYGBgDQoNCmBgYHtyIG51bV9taW5rLCBlY2hvPUZBTFNFfQ0KIyBjb252ZXJ0IHRoZSBkaXN0YW5jZSB0byBudW1lcmljDQpkZWx0YSA8LSBhcy5udW1lcmljKG1pbmtfZCkNCmBgYA0KDQoNCmBgYHtyIG51bV9kX2Nvb3JkcywgZWNobz1GQUxTRX0NCiMgQWxsIHRoZSBjb29yZHMgaW4gb25lIGNvbHVtbg0KRCA8LSBhcy5udW1lcmljKGRpc3QoY29vcmRzKSkNCmBgYA0KDQpgYGB7ciBpbmRleDEsIGVjaG89RkFMU0V9DQojIGNyZWF0ZSBhIHNxdWFyZSBtYXRyaXggd2l0aCBkaW1lbnNpb25zIGZyb20gdGhlIHJvd3Mgb2YgY29vcmRzDQojIG4gYXMgcm93cyANCm4gPSBucm93KGNvb3JkcykNCg0KIyBpbmRleCBhcyBlbXB5dCBtYXRyaXgNCmluZGV4IDwtIG1hdHJpeCgxOm4sIG5yb3cgPSBuLCBuY29sID0gbikNCg0KIyBnZXQgaW5kZXggb2YgdGhlIGxvd2VyIHRyaWFuZ2xlIG9mIHRoZSBpbmRleCBtYXRyaXggYW5kIGNvbnZlcnQgaXQgdG8gbnVtZXJpYw0KaW5kZXgxIDwtIGFzLm51bWVyaWMoaW5kZXhbbG93ZXIudHJpKGluZGV4KV0pDQoNCmBgYA0KDQpgYGB7ciBpbmRleDIsIGVjaG89RkFMU0V9DQojIHNhbWUgcHJvY2VkdXINCm4gPSBucm93KGNvb3JkcykNCg0KaW5kZXggPC0gbWF0cml4KDE6biwgbnJvdz1uLCBuY29sPW4sIGJ5cm93ID0gVCkNCg0KaW5kZXgyIDwtIGFzLm51bWVyaWMoaW5kZXhbbG93ZXIudHJpKGluZGV4KV0pDQpgYGANCg0KYGBge3Igcm93bmFtZXMsIGVjaG89RkFMU0V9DQojIGkgZG9udCB3YW50IHRvIGVkaXQgb3JpZ2luYWwgZGF0YQ0KYmFzZWJhbGwzIDwtIGJhc2ViYWxsDQoNCnJvd25hbWVzKGJhc2ViYWxsMykgPC1iYXNlYmFsbDNbICwxXQ0KDQpgYGANCg0KYGBge3IgcGxvdF9zfQ0KIyBwbG90bHkNCnBsb3RfbHkoKSU+JQ0KICBhZGRfbWFya2Vycyh4PX5kZWx0YSwgeT1+RCwgaG92ZXJpbmZvID0gJ3RleHQnLA0KICAgICAgICB0ZXh0ID0gfnBhc3RlKCdPYmoxOiAnLCByb3duYW1lcyhiYXNlYmFsbDMpW2luZGV4MV0sDQogICAgICAgICAgICAgICAgICAgICAgJzxicj4gT2JqMjogJywgcm93bmFtZXMoYmFzZWJhbGwzKVtpbmRleDJdKSkgJT4lDQogICNpZiBub25tZXRyaWMgTURTIGlub2x2ZWQNCiAgYWRkX2xpbmVzKHg9fnNoZXAkeCwgeT1+c2hlcCR5ZikgJT4lDQogIGxheW91dCh0aXRsZSA9ICJTaGVwYXJkJ3MgcGxvdCIpDQpgYGANCg0KDQpgYGB7ciBxdWVzdGlvbjRfMiwgZWNobz1GQUxTRX0NCiMgZ2V0IE1EUyB2YXJpYWJsZSBWMiBhbmQgY2JpbmQgd2l0aCBwb2ludHMgZnJvbSBpc29NRFMNCmQ0IDwtIGNiaW5kKGJhc2ViYWxsWyAsMToyXSwgY29vcmRzWywyXSwgYmFzZWJhbGwyWyxdKQ0KDQojIHJlbmFtZSBjb2wzIHRvIFYyDQpjb2xuYW1lcyhkNClbM10gPC0gYygiVjIiKQ0KYGBgDQoNCg0KYGBge3IgZnhuMiwgZWNobz1GQUxTRX0NCiMgZnVuY3Rpb24gdG8gc3VjY2Vzc2l2ZWx5IGdldCBwbG90cyBvZiBWMiB2cyBvdGhlciB2YXJpYWJsZXMNCm15cGxvdCA8LWZ1bmN0aW9uKGRmLCB5X3N0cmluZyl7DQogIGdncGxvdChkZiwgYWVzX3N0cmluZyh4ID0gIlYyIiwgeSA9IHlfc3RyaW5nLCBjb2xvciA9ICJMZWFndWUiKSkrDQogICAgZ2VvbV9wb2ludCgpKw0KICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGNvbG9yID0gImJsYWNrIikrDQogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSAiYmxhY2siKQ0KfQ0KYGBgDQoNCmBgYHtyIGhycGd9DQojIFZhcmlhYmxlcyB0aGF0IHNlZW0gdG8gaGF2ZSBzdHJvbmdlc3QgcG9zdGl2ZSByZWxhdGlvbnNoaXANCiMgSFIgcGVyIGdhbWU6DQpteXBsb3QoZDQsICJIUi5wZXIuZ2FtZSIpDQpgYGANCg0KYGBge3IgeDNifQ0KIyBYM0INCm15cGxvdChkNCwgIlgzQiIpDQpgYGANCg0KUGVyIHRoZSBwbG90LCBIUiBwZXIgZ2FtZSBhbmQgSFIgaGF2ZSB0aGUgc2FtZSBzY2F0dGVyIHBvaW50cy4gVGhlIHR3byBoYXZlIHN0cm9uZ2VzdCBwb3NpdGl2ZSBjb25uZWN0aW9uIHRvIFYyIHdoaWxlIFgzQiBoYXMgdGhlIHN0cm9uZ2VzdCBuZWdhdGl2ZSBjb25uZWN0aW9uIHRvIFYyLg0KDQojIyMgQXBwZW5kaXgNCg0KYGBge3IgcmVmLmxhYmVsPWtuaXRyOjphbGxfbGFiZWxzKCksIGVjaG8gPSBULCBldmFsID0gRn0NCg0KYGBgDQoNCiMjIyBSZWZlcmVuY2VzDQoNCg==